//
//  File.swift
//  
//
//  Created by Jiang Chencheng on 2024/9/2.
//

import Vapor
import Fluent

struct UserController: RouteCollection {
    func boot(routes: any Vapor.RoutesBuilder) throws {
        
        routes.post("signin", use: signin)

        routes.post("signup", use: signup)
        
        let userProtected = routes
            .grouped("user")
            .grouped(SessionToken.authenticator(), SessionToken.guardMiddleware())
    
        userProtected.get("info",use: userinfo)
    
        
    }
    
    @Sendable
    func signin(req: Request) async throws -> BizResponse<UserTokenResp> {
        
        let body = try req.content.decode(LoginReq.self)

        guard let user = try await User
            .query(on: req.db)
            .filter(\.$email == body.email)
            .first() 
        else {
            throw BizError.userNotFound
        }
        
        let isVerified = try req.password.verify(body.password, created: user.password)
        if !isVerified { throw BizError.passwordInvalid }
        
        let resp = try generateTokenResponse(with: user, req: req)
        return resp
    }
    
    @Sendable
    func signup(req: Request) async throws -> BizResponse<UserTokenResp>  {
        
        let body = try req.content.decode(RegisterReq.self)
        
        let email = body.email
        let password = try req.password.hash(body.password)
        
        let isExisted = try await User
            .query(on: req.db)
            .filter(\.$email == email)
            .exist()
        if isExisted { throw BizError.userExisted }
        
        let user = User(email: body.email, password: password)
    
        try await req.db.transaction { transaction in
            try await user.create(on: transaction)
            let room = try Room(ownerID: user.requireID())
            try await room.save(on: transaction)
        }
    
        let resp = try generateTokenResponse(with: user, req: req)
        return resp
    }
    
    
    
    @Sendable
    func userinfo(req: Request) async throws -> BizResponse<UserDTO> {
        let sessionToken = try req.auth.require(SessionToken.self)
        guard let user = try await User
            .query(on: req.db)
            .filter(\.$id == sessionToken.userId)
            .first() 
        else {
            throw BizError.userNotFound
        }
        return BizResponse(data: user.toDTO())
    }
    
    
}

private extension UserController {
    
    
    /// 登录/注册接口生成UserToken返回信息
    /// - Parameters:
    ///   - user: 当前用户
    ///   - req: 当前请求
    /// - Returns: UserToken返回信息
    func generateTokenResponse(with user: User, req: Request) throws -> BizResponse<UserTokenResp> {
        let payload = try SessionToken(with: user)
        let token = try req.jwt.sign(payload)
        let resp = UserTokenResp(user: user.toDTO(), token: token)
        return BizResponse(data: resp)
    }
    
}
